package bigbrother.modules;

import bigbrother.IrcBotContext;
import bigbrother.command.Command;
import org.jibble.pircbot.DccChat;
import org.jibble.pircbot.DccFileTransfer;
import org.jibble.pircbot.User;

import java.util.*;
import java.util.logging.Logger;

/**
 * Common functionality for modules.
 * <p/>
 * Provides a few abstract protected methods that modules should implement.
 *
 * @author Hans Haggstrom
 */
public abstract class AbstractModule
        implements Module
{

    //======================================================================
    // Private Fields

    private final String myIdentifier;

    private final List<Command> myCommands = new ArrayList<Command>();

    private final Logger myLogger = Logger.getLogger( getClass().getName() );

    private IrcBotContext myContext;
    private Properties myProperties;

    //======================================================================
    // Public Methods

    //----------------------------------------------------------------------
    // ChannelListener Implementation

    public void onConnect()
    {

    }


    public void onDisconnect()
    {

    }


    public void onServerResponse( final int code, final String response )
    {

    }


    public void onUserList( final String channel, final User[] users )
    {

    }


    public void onMessage( final String channel,
                           final String sender,
                           final String login,
                           final String hostname,
                           final String message )
    {

    }


    public void onPrivateMessage( final String sender, final String login, final String hostname, final String message )
    {

    }


    public void onAction( final String sender,
                          final String login,
                          final String hostname,
                          final String target,
                          final String action )
    {

    }


    public void onNotice( final String sourceNick,
                          final String sourceLogin,
                          final String sourceHostname,
                          final String target,
                          final String notice )
    {

    }


    public void onJoin( final String channel, final String sender, final String login, final String hostname )
    {

    }


    public void onPart( final String channel, final String sender, final String login, final String hostname )
    {

    }


    public void onNickChange( final String oldNick, final String login, final String hostname, final String newNick )
    {

    }


    public void onKick( final String channel,
                        final String kickerNick,
                        final String kickerLogin,
                        final String kickerHostname,
                        final String recipientNick,
                        final String reason )
    {

    }


    public void onQuit( final String sourceNick,
                        final String sourceLogin,
                        final String sourceHostname,
                        final String reason )
    {

    }


    public void onTopic( final String channel, final String topic )
    {

    }


    public void onTopic( final String channel,
                         final String topic,
                         final String setBy,
                         final long date,
                         final boolean changed )
    {

    }


    public void onChannelInfo( final String channel, final int userCount, final String topic )
    {

    }


    public void onMode( final String channel,
                        final String sourceNick,
                        final String sourceLogin,
                        final String sourceHostname,
                        final String mode )
    {

    }


    public void onUserMode( final String targetNick,
                            final String sourceNick,
                            final String sourceLogin,
                            final String sourceHostname,
                            final String mode )
    {

    }


    public void onOp( final String channel,
                      final String sourceNick,
                      final String sourceLogin,
                      final String sourceHostname,
                      final String recipient )
    {

    }


    public void onDeop( final String channel,
                        final String sourceNick,
                        final String sourceLogin,
                        final String sourceHostname,
                        final String recipient )
    {

    }


    public void onVoice( final String channel,
                         final String sourceNick,
                         final String sourceLogin,
                         final String sourceHostname,
                         final String recipient )
    {

    }


    public void onDeVoice( final String channel,
                           final String sourceNick,
                           final String sourceLogin,
                           final String sourceHostname,
                           final String recipient )
    {

    }


    public void onSetChannelKey( final String channel,
                                 final String sourceNick,
                                 final String sourceLogin,
                                 final String sourceHostname,
                                 final String key )
    {

    }


    public void onRemoveChannelKey( final String channel,
                                    final String sourceNick,
                                    final String sourceLogin,
                                    final String sourceHostname,
                                    final String key )
    {

    }


    public void onSetChannelLimit( final String channel,
                                   final String sourceNick,
                                   final String sourceLogin,
                                   final String sourceHostname,
                                   final int limit )
    {

    }


    public void onRemoveChannelLimit( final String channel,
                                      final String sourceNick,
                                      final String sourceLogin,
                                      final String sourceHostname )
    {

    }


    public void onSetChannelBan( final String channel,
                                 final String sourceNick,
                                 final String sourceLogin,
                                 final String sourceHostname,
                                 final String hostmask )
    {

    }


    public void onRemoveChannelBan( final String channel,
                                    final String sourceNick,
                                    final String sourceLogin,
                                    final String sourceHostname,
                                    final String hostmask )
    {

    }


    public void onSetTopicProtection( final String channel,
                                      final String sourceNick,
                                      final String sourceLogin,
                                      final String sourceHostname )
    {

    }


    public void onRemoveTopicProtection( final String channel,
                                         final String sourceNick,
                                         final String sourceLogin,
                                         final String sourceHostname )
    {

    }


    public void onSetNoExternalMessages( final String channel,
                                         final String sourceNick,
                                         final String sourceLogin,
                                         final String sourceHostname )
    {

    }


    public void onRemoveNoExternalMessages( final String channel,
                                            final String sourceNick,
                                            final String sourceLogin,
                                            final String sourceHostname )
    {

    }


    public void onSetInviteOnly( final String channel,
                                 final String sourceNick,
                                 final String sourceLogin,
                                 final String sourceHostname )
    {

    }


    public void onRemoveInviteOnly( final String channel,
                                    final String sourceNick,
                                    final String sourceLogin,
                                    final String sourceHostname )
    {

    }


    public void onSetModerated( final String channel,
                                final String sourceNick,
                                final String sourceLogin,
                                final String sourceHostname )
    {

    }


    public void onRemoveModerated( final String channel,
                                   final String sourceNick,
                                   final String sourceLogin,
                                   final String sourceHostname )
    {

    }


    public void onSetPrivate( final String channel,
                              final String sourceNick,
                              final String sourceLogin,
                              final String sourceHostname )
    {

    }


    public void onRemovePrivate( final String channel,
                                 final String sourceNick,
                                 final String sourceLogin,
                                 final String sourceHostname )
    {

    }


    public void onSetSecret( final String channel,
                             final String sourceNick,
                             final String sourceLogin,
                             final String sourceHostname )
    {

    }


    public void onRemoveSecret( final String channel,
                                final String sourceNick,
                                final String sourceLogin,
                                final String sourceHostname )
    {

    }


    public void onInvite( final String targetNick,
                          final String sourceNick,
                          final String sourceLogin,
                          final String sourceHostname,
                          final String channel )
    {

    }


    public void onDccSendRequest( final String sourceNick,
                                  final String sourceLogin,
                                  final String sourceHostname,
                                  final String filename,
                                  final long address,
                                  final int port,
                                  final int size )
    {

    }


    public void onDccChatRequest( final String sourceNick,
                                  final String sourceLogin,
                                  final String sourceHostname,
                                  final long address,
                                  final int port )
    {

    }


    public void onIncomingFileTransfer( final DccFileTransfer transfer )
    {
    }


    public void onFileTransferFinished( final DccFileTransfer transfer, final Exception e )
    {

    }


    public void onIncomingChatRequest( final DccChat chat )
    {

    }


    public void onUnknown( final String line )
    {

    }

    //----------------------------------------------------------------------
    // Module Implementation

    public final synchronized String getIdentifier()
    {
        return myIdentifier;
    }

    public void start( final IrcBotContext context, final Properties properties )
    {
        myContext = context;
        myProperties = properties;

        onModuleStarted();
    }


    public final void stop()
    {
        onModuleStopped();
    }


    public final void handleCommand( final String channel,
                                     final String sender,
                                     final String login,
                                     final String hostname,
                                     final String commandName,
                                     final String parameters )
    {
        for ( Command command : myCommands )
        {
            if ( command.getCommandName().equalsIgnoreCase( commandName ) )
            {
                // Invoke command
                final String reply = command.doCommand( channel, sender, login, hostname, parameters );

                // If we got a reply, send it
                if ( reply != null )
                {
                    // Get target
                    String target = channel;
                    if ( target == null )
                    {
                        target = sender;
                    }

                    getContext().sendMultilineMessage( reply, target );
                }

                return; // Command found and handled
            }
        }
    }


    public final Collection<Command> getCommands()
    {
        return Collections.unmodifiableCollection( myCommands );
    }

    //----------------------------------------------------------------------
    // Other Public Methods

    /**
     * Adds the specified Command.
     *
     * @param addedCommand should not be null or already added.
     */
    public void registerCommand( Command addedCommand )
    {
        if ( addedCommand == null )
        {
            throw new IllegalArgumentException( "addedCommand should not be null" );
        }

        myCommands.add( addedCommand );
    }


    /**
     * @return the irc bot context that provides methods for sending messages and such.
     */
    public final IrcBotContext getContext()
    {
        return myContext;
    }

    //======================================================================
    // Protected Methods

    //----------------------------------------------------------------------
    // Protected Constructors

    protected AbstractModule( final String identifier )
    {
        myIdentifier = identifier;
    }

    //----------------------------------------------------------------------
    // Abstract Protected Methods

    /**
     * Called after the irc bot connects to a network, and the module is started. Also called if modules are started for
     * some other reason.
     */
    protected abstract void onModuleStarted();

    /**
     * Called when the irc bot is shotdown and disconnects from a network, and the module is stopped. Also called if
     * modules are stopped for some other reason.
     * <p/>
     * Note that if the irc bot process is just killed for some reason, this method will not be called, so modules
     * should not rely on it.
     */
    protected abstract void onModuleStopped();

    //----------------------------------------------------------------------
    // Other Protected Methods

    /**
     * @return a logger for logging error messages with.
     */
    protected final Logger getLogger()
    {
        return myLogger;
    }


    /**
     * Queries the properties defined in the configuration file.
     *
     * @param propertyName name of property to get.
     * @param defaultValue value to use if property is not available.
     *
     * @return the specified property value, or defaultValue if not found.
     */
    protected final String getProperty( String propertyName, String defaultValue )
    {
        return myProperties.getProperty( propertyName, defaultValue );
    }

    // TODO: Add a getModuleProperty and a setModuleProperty, that access and modify the property file, and use module prefixes to enforce a namespace.  Should probably filter newlines.


}
